// 处理控制参数处理边线后可能出现的问题

import { crossLines } from './math'

import type { Temp } from './_imports'

export { fixRayLoops }

/** 将偏移后的边线修正为闭合的多边形 */
function fixRayLoops(rayLoops: Temp.Ray[][]): Temp.Ray[][] {
  let result = fixHoles(rayLoops)
  let lengthBefore = result.reduce((a, b) => a + b.length, 0)
  let changed = true

  // 实测需要多次循环，因为修正后可能再次出现交叉
  while (changed) {
    result = fixIntersects(result)
    const lengthAfter = result.reduce((a, b) => a + b.length, 0)
    changed = lengthBefore !== lengthAfter
    lengthBefore = lengthAfter
  }

  return fixGaps(result)
}

/** 处理圈内边线相互交叉的情况 **/
function fixIntersects(rayLoops: Temp.Ray[][]): Temp.Ray[][] {
  return rayLoops.map((rayLoop) => {
    const result: Temp.Ray[] = []

    for (let i = 0; i < rayLoop.length; i++) {
      const thisRay = rayLoop[i]!
      let intersected = false
      // 排除相邻的，遍历之后的线段寻找与其之后相交的线段
      for (let j = i + 2; j < rayLoop.length; j++) {
        if (i === 0 && j === rayLoop.length - 1) continue // 忽略首尾相连的情况

        const nextRay = rayLoop[j]!
        const intersection = crossLines(thisRay, nextRay)
        if (intersection) {
          result.push({
            start: thisRay.start,
            end: intersection.clone(),
            direction: intersection.clone().sub(thisRay.start),
          })
          result.push({
            start: intersection.clone(),
            end: nextRay.end,
            direction: nextRay.end.clone().sub(intersection),
          })
          i = j
          intersected = true
          break
        }
      }
      if (!intersected) {
        result.push(thisRay)
      }
    }

    return result
  })
}

/** 处理内外圈交错的情况 **/
function fixHoles(rayLoops: Temp.Ray[][]): Temp.Ray[][] {
  return rayLoops.filter((hole, i) => {
    if (i === 0) {
      // 外圈不用检查
      return true
    } else {
      // 内圈不得与外圈相交
      return !rayLoops[0]!.find((outterRay) => {
        // 有交点则返回true
        return hole.find((holeRay) => {
          return crossLines(outterRay, holeRay) ? true : false
        })
      })
    }
  })
}

/** 处理边线不连续的情况 */
function fixGaps(rayLoops: Temp.Ray[][]): Temp.Ray[][] {
  return rayLoops.map((rayloop) => {
    const result: Temp.Ray[] = []

    rayloop.forEach((ray, i) => {
      result.push(ray)

      // 下一个起点须与该终点重合，否则加入该终点到下一个起点的线段
      const nextRay = rayloop[i === rayloop.length - 1 ? 0 : i + 1]!
      if (!ray.end.equals(nextRay.start)) {
        result.push({
          start: ray.end,
          end: nextRay.start,
          direction: nextRay.start.clone().sub(ray.end),
        })
      }
    })

    return result
  })
}
